#include "HCNetSDK.h"

#include <stdio.h>
#include <time.h>
#include <unistd.h>

#include <iostream>
using namespace std;
using namespace HC_NET_SDK;
FILE *m_pFile;
LONG  lPort;
static char g_szDevIp[32]     = "xxx.xxx.xxx.xxx";
static WORD g_nPort = 8000; // tcp 连接端口，需与期望登录设备页面 tcp 端口配置一致
static char g_szUserName[64] = "admin";
static char g_szPasswd[64]   = "admin123";
int save_h264_file(BYTE *frame, DWORD dwBufSize)
{
    if (NULL != frame) {
        static int find_I = 0;
        if (!find_I) {
            if (frame[0] == 0x00 && frame[1] == 0x00 && frame[2] == 0x00 && frame[3] == 0x01) {
                if ((frame[4] & 0x1f) == 7) {
                    find_I = 1;
                    fwrite(frame, 1, dwBufSize, m_pFile);
                    fflush(m_pFile);
                }
            }
        } else {
            fwrite(frame, 1, dwBufSize, m_pFile);
            fflush(m_pFile);
        }
    }

    return 0;
}
void CALLBACK g_ExceptionCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize,
                                  DWORD dwUser)
{
    char tempbuf[256] = {0};
    switch (dwDataType) {
    case NET_DVR_SYSHEAD: {
        printf("----------reconnect--------%d\n", time(NULL));
        break;
    }
    case NET_DVR_STREAMDATA:
        save_h264_file(pBuffer, dwBufSize);
        break;
    }
}

void CALLBACK cbStdDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize,
                                DWORD dwUser)
{
    char tempbuf[256] = {0};
    switch (dwDataType) {
    case NET_DVR_SYSHEAD: {
        printf("----------reconnect--------%d\n", dwBufSize);
        break;
    }
    case NET_DVR_STD_VIDEODATA:
        save_h264_file(pBuffer, dwBufSize);
        break;
    }
}

void CALLBACK esDataCallBack(LONG lPreviewHandle, NET_DVR_PACKET_INFO_EX *pstruPackInfo, void* pUser)
{
    printf("-----------------%d, %d\n", pstruPackInfo->dwPacketSize, pstruPackInfo->dwPacketType);
    if (pstruPackInfo->dwPacketType == 1) {
        // 1 -video I frame，2- video B frame， 3- video P frame， 10- audio packet， 11- private packet
        printf("===============================%s=========================\n", pstruPackInfo->dwPacketType);
    }
    if (pstruPackInfo->dwPacketType == 1 || (pstruPackInfo->dwPacketType == 2) || (pstruPackInfo->dwPacketType == 3)) {
        save_h264_file(pstruPackInfo->pPacketBuffer, pstruPackInfo->dwPacketSize);
    }
}

int main()
{
    // 初始化
    NET_DVR_Init();
    // 设置连接时间与重连时间
    NET_DVR_SetConnectTime(2000, 1);
    NET_DVR_SetReconnect(10000, true);

    std::string file = "./test.h264";
    if (nullptr == m_pFile) {
        if (!access(file.c_str(), F_OK)) {
            remove(file.c_str());
        }

        m_pFile = fopen(file.c_str(), "wb");
    }

    // 注册设备
    LONG                   lUserID;
    NET_DVR_DEVICEINFO_V30 struDeviceInfo;
    lUserID = NET_DVR_Login_V30(g_szDevIp, g_nPort, g_szUserName, g_szPasswd, &struDeviceInfo);
    if (lUserID < 0) {
        printf("Login error, %x\n", NET_DVR_GetLastError());
        NET_DVR_Cleanup();
        return 0;
    }

    // 启动预览并设置回调数据流
    LONG                lRealPlayHandle;
    NET_DVR_PREVIEWINFO struPlayInfo = {0};
    // struPlayInfo.hPlayWnd = hWnd;  // 需要 SDK 解码时句柄设为有效值，仅取流不解码时可设为空
    struPlayInfo.hPlayWnd = NULL; // 需要 SDK 解码时句柄设为有效值，仅取流不解码时可设为空
    struPlayInfo.lChannel     = 1; // 预览通道号
    struPlayInfo.dwStreamType = 0; // 0-主码流，1-子码流，2-码流 3，3-码流 4，以此类推
    struPlayInfo.dwLinkMode =
        0; // 0- TCP 方式，1- UDP 方式，2- 多播方式，3- RTP 方式，4-RTP/RTSP，5-RSTP/HTTP
    struPlayInfo.bBlocked = 1; // 0- 非阻塞取流，1- 阻塞取流
    lRealPlayHandle       = NET_DVR_RealPlay_V40(lUserID, &struPlayInfo, NULL, NULL);
    if (lRealPlayHandle < 0) {
        printf("NET_DVR_RealPlay_V40 error\n");
        NET_DVR_Logout(lUserID);
        NET_DVR_Cleanup();
        return 0;
    }
    // NET_DVR_SetRealDataCallBack(lRealPlayHandle, g_ExceptionCallBack, NULL);
    // NET_DVR_SetStandardDataCallBack(lRealPlayHandle, cbStdDataCallBack, NULL);
    // NET_DVR_SaveRealData(lRealPlayHandle, file);
    NET_DVR_SetESRealPlayCallBack(lRealPlayHandle, esDataCallBack, NULL);
    pause();
    // 关闭预览
    NET_DVR_StopRealPlay(lRealPlayHandle);
    // 注销用户
    NET_DVR_Logout(lUserID);
    NET_DVR_Cleanup();
    return 0;
}
